home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / tcsh / Source / glob.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-21  |  16.3 KB  |  681 lines

  1. /*
  2.  * Copyright (c) 1989 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Guido van Rossum.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36. #if defined(LIBC_SCCS) && !defined(lint)
  37. static char sccsid[] = "@(#)glob.c    5.12 (Berkeley) 6/24/91";
  38. #endif /* LIBC_SCCS and not lint */
  39. /*
  40.  * Glob: the interface is a superset of the one defined in POSIX 1003.2,
  41.  * draft 9.
  42.  *
  43.  * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
  44.  *
  45.  * Optional extra services, controlled by flags not defined by POSIX:
  46.  *
  47.  * GLOB_QUOTE:
  48.  *    Escaping convention: \ inhibits any special meaning the following
  49.  *    character might have (except \ at end of string is retained).
  50.  * GLOB_MAGCHAR:
  51.  *    Set in gl_flags if pattern contained a globbing character.
  52.  * GLOB_ALTNOT:
  53.  *    Use ^ instead of ! for "not".
  54.  * gl_matchc:
  55.  *    Number of matches in the current invocation of glob.
  56.  */
  57.  
  58. #ifdef notdef
  59. #include <sys/types.h>
  60. #include <sys/param.h>
  61. #include <sys/stat.h>
  62. #include <dirent.h>
  63. #include <ctype.h>
  64. typedef void * ptr_t;
  65. #endif
  66.  
  67. #define Char __Char
  68. #include "sh.h"
  69. #undef Char
  70. #undef QUOTE
  71. #undef TILDE
  72. #undef META
  73. #undef CHAR
  74. #undef ismeta
  75. #undef Strchr
  76.  
  77. #include "glob.h"
  78.  
  79. #ifndef S_ISDIR
  80. #define S_ISDIR(a)    (((a) & S_IFMT) == S_IFDIR)
  81. #endif
  82.  
  83. #if !defined(S_ISLNK) && defined(S_IFLNK)
  84. #define S_ISLNK(a)    (((a) & S_IFMT) == S_IFLNK)
  85. #endif
  86.  
  87. #if !defined(S_ISLNK) && !defined(lstat)
  88. #define lstat stat
  89. #endif
  90.  
  91. typedef unsigned short Char;
  92.  
  93. static    int     glob1         __P((Char *, glob_t *, int));
  94. static    int     glob2        __P((Char *, Char *, Char *, glob_t *, int));
  95. static    int     glob3        __P((Char *, Char *, Char *, Char *,
  96.                      glob_t *, int));
  97. static    int     globextend    __P((Char *, glob_t *));
  98. static    int     match        __P((Char *, Char *, Char *, int));
  99. static    int     compare    __P((const ptr_t, const ptr_t));
  100. static     DIR    *Opendir    __P((Char *));
  101. #ifdef S_IFLNK
  102. static    int     Lstat        __P((Char *, struct stat *));
  103. #endif
  104. static     Char     *Strchr        __P((Char *, int));
  105. #ifdef DEBUG
  106. static    void     qprintf    __P((Char *));
  107. #endif
  108.  
  109. #define    DOLLAR        '$'
  110. #define    DOT        '.'
  111. #define    EOS        '\0'
  112. #define    LBRACKET    '['
  113. #define    NOT        '!'
  114. #define ALTNOT        '^'
  115. #define    QUESTION    '?'
  116. #define    QUOTE        '\\'
  117. #define    RANGE        '-'
  118. #define    RBRACKET    ']'
  119. #define    SEP        '/'
  120. #define    STAR        '*'
  121. #define    TILDE        '~'
  122. #define    UNDERSCORE    '_'
  123.  
  124. #define    M_META        0x8000
  125. #define M_PROTECT    0x4000
  126. #define    M_MASK        0xffff
  127. #define    M_ASCII        0x00ff
  128.  
  129. #define    CHAR(c)        ((c)&M_ASCII)
  130. #define    META(c)        ((c)|M_META)
  131. #define    M_ALL        META('*')
  132. #define    M_END        META(']')
  133. #define    M_NOT        META('!')
  134. #define    M_ALTNOT    META('^')
  135. #define    M_ONE        META('?')
  136. #define    M_RNG        META('-')
  137. #define    M_SET        META('[')
  138. #define    ismeta(c)    (((c)&M_META) != 0)
  139.  
  140. /*
  141.  * Need to dodge two kernel bugs:
  142.  * opendir("") != opendir(".")
  143.  * NAMEI_BUG: on plain files trailing slashes are ignored in some kernels.
  144.  *            POSIX specifies that they should be ignored in directories.
  145.  */
  146.  
  147. /*
  148.  * For operating systems with single case filenames (OS/2)
  149.  */
  150. #ifdef CASE_INSENSITIVE
  151. # define samecase(x) (isupper(x) ? tolower(x) : (x))
  152. #else
  153. # define samecase(x) (x)
  154. #endif /* CASE_INSENSITIVE */
  155.  
  156. static DIR *
  157. Opendir(str)
  158.     register Char *str;
  159. {
  160.     char    buf[MAXPATHLEN];
  161.     register char *dc = buf;
  162.  
  163.     if (!*str)
  164.     return (opendir("."));
  165.     while ((*dc++ = *str++) != '\0')
  166.     continue;
  167.     return (opendir(buf));
  168. }
  169.  
  170. #ifdef S_IFLNK
  171. static int
  172. Lstat(fn, sb)
  173.     register Char *fn;
  174.     struct stat *sb;
  175. {
  176.     char    buf[MAXPATHLEN];
  177.     register char *dc = buf;
  178.  
  179.     while ((*dc++ = *fn++) != '\0')
  180.     continue;
  181. # ifdef NAMEI_BUG
  182.     {
  183.     int     st;
  184.  
  185.     st = lstat(buf, sb);
  186.     if (*buf)
  187.         dc--;
  188.     return (*--dc == '/' && !S_ISDIR(sb->st_mode) ? -1 : st);
  189.     }
  190. # else
  191.     return (lstat(buf, sb));
  192. # endif    /* NAMEI_BUG */
  193. }
  194. #else
  195. #define Lstat Stat
  196. #endif /* S_IFLNK */
  197.  
  198. static int
  199. Stat(fn, sb)
  200.     register Char *fn;
  201.     struct stat *sb;
  202. {
  203.     char    buf[MAXPATHLEN];
  204.     register char *dc = buf;
  205.  
  206.     while ((*dc++ = *fn++) != '\0')
  207.     continue;
  208. #ifdef NAMEI_BUG
  209.     {
  210.     int     st;
  211.  
  212.     st = stat(buf, sb);
  213.     if (*buf)
  214.         dc--;
  215.     return (*--dc == '/' && !S_ISDIR(sb->st_mode) ? -1 : st);
  216.     }
  217. #else
  218.     return (stat(buf, sb));
  219. #endif /* NAMEI_BUG */
  220. }
  221.  
  222. static Char *
  223. Strchr(str, ch)
  224.     Char *str;
  225.     int ch;
  226. {
  227.     do
  228.     if (*str == ch)
  229.         return (str);
  230.     while (*str++);
  231.     return (NULL);
  232. }
  233.  
  234. #ifdef DEBUG
  235. static void
  236. qprintf(s)
  237. Char *s;
  238. {
  239.     Char *p;
  240.  
  241.     for (p = s; *p; p++)
  242.     printf("%c", *p & 0xff);
  243.     printf("\n");
  244.     for (p = s; *p; p++)
  245.     printf("%c", *p & M_PROTECT ? '"' : ' ');
  246.     printf("\n");
  247.     for (p = s; *p; p++)
  248.     printf("%c", *p & M_META ? '_' : ' ');
  249.     printf("\n");
  250. }
  251. #endif /* DEBUG */
  252.  
  253. static int
  254. compare(p, q)
  255.     const ptr_t  p, q;
  256. {
  257.     return (strcmp(*(char **) p, *(char **) q));
  258. }
  259.  
  260. /*
  261.  * The main glob() routine: compiles the pattern (optionally processing
  262.  * quotes), calls glob1() to do the real pattern matching, and finally
  263.  * sorts the list (unless unsorted operation is requested).  Returns 0
  264.  * if things went well, nonzero if errors occurred.  It is not an error
  265.  * to find no matches.
  266.  */
  267. int
  268. glob(pattern, flags, errfunc, pglob)
  269.     const char *pattern;
  270.     int     flags;
  271.     int     (*errfunc) __P((char *, int));
  272.     glob_t *pglob;
  273. {
  274.     int     err, oldpathc;
  275.     Char *bufnext, *bufend, *compilebuf, m_not;
  276.     const unsigned char *compilepat, *patnext;
  277.     int     c, not;
  278.     Char patbuf[MAXPATHLEN + 1], *qpatnext;
  279.     int     no_match;
  280.  
  281.     patnext = (unsigned char *) pattern;
  282.     if (!(flags & GLOB_APPEND)) {
  283.     pglob->gl_pathc = 0;
  284.     pglob->gl_pathv = NULL;
  285.     if (!(flags & GLOB_DOOFFS))
  286.         pglob->gl_offs = 0;
  287.     }
  288.     pglob->gl_flags = flags & ~GLOB_MAGCHAR;
  289.     pglob->gl_errfunc = errfunc;
  290.     oldpathc = pglob->gl_pathc;
  291.     pglob->gl_matchc = 0;
  292.  
  293.     if (pglob->gl_flags & GLOB_ALTNOT) {
  294.     not = ALTNOT;
  295.     m_not = M_ALTNOT;
  296.     }
  297.     else {
  298.     not = NOT;
  299.     m_not = M_NOT;
  300.     }
  301.  
  302.     bufnext = patbuf;
  303.     bufend = bufnext + MAXPATHLEN;
  304.     compilebuf = bufnext;
  305.     compilepat = patnext;
  306.  
  307.     no_match = *patnext == not;
  308.     if (no_match)
  309.     patnext++;
  310.  
  311.     if (flags & GLOB_QUOTE) {
  312.     /* Protect the quoted characters */
  313.     while (bufnext < bufend && (c = *patnext++) != EOS) 
  314.         if (c == QUOTE) {
  315.         if ((c = *patnext++) == EOS) {
  316.             c = QUOTE;
  317.             --patnext;
  318.         }
  319.         *bufnext++ = (Char) (c | M_PROTECT);
  320.         }
  321.         else
  322.         *bufnext++ = (Char) c;
  323.     }
  324.     else 
  325.     while (bufnext < bufend && (c = *patnext++) != EOS) 
  326.         *bufnext++ = (Char) c;
  327.     *bufnext = EOS;
  328.  
  329.     bufnext = patbuf;
  330.     qpatnext = patbuf;
  331.     /* we don't need to check for buffer overflow any more */
  332.     while ((c = *qpatnext++) != EOS) {
  333.     switch (c) {
  334.     case LBRACKET:
  335.         c = *qpatnext;
  336.         if (c == not)
  337.         ++qpatnext;
  338.         if (*qpatnext == EOS ||
  339.         Strchr(qpatnext + 1, RBRACKET) == NULL) {
  340.         *bufnext++ = LBRACKET;
  341.         if (c == not)
  342.             --qpatnext;
  343.         break;
  344.         }
  345.         pglob->gl_flags |= GLOB_MAGCHAR;
  346.         *bufnext++ = M_SET;
  347.         if (c == not)
  348.         *bufnext++ = m_not;
  349.         c = *qpatnext++;
  350.         do {
  351.         *bufnext++ = CHAR(c);
  352.         if (*qpatnext == RANGE &&
  353.             (c = qpatnext[1]) != RBRACKET) {
  354.             *bufnext++ = M_RNG;
  355.             *bufnext++ = CHAR(c);
  356.             qpatnext += 2;
  357.         }
  358.         } while ((c = *qpatnext++) != RBRACKET);
  359.         *bufnext++ = M_END;
  360.         break;
  361.     case QUESTION:
  362.         pglob->gl_flags |= GLOB_MAGCHAR;
  363.         *bufnext++ = M_ONE;
  364.         break;
  365.     case STAR:
  366.         pglob->gl_flags |= GLOB_MAGCHAR;
  367.         /* collapse adjacent stars to one, to avoid
  368.          * exponential behavior
  369.          */
  370.         if (bufnext == patbuf || bufnext[-1] != M_ALL)
  371.         *bufnext++ = M_ALL;
  372.         break;
  373.     default:
  374.         *bufnext++ = CHAR(c);
  375.         break;
  376.     }
  377.     }
  378.     *bufnext = EOS;
  379. #ifdef DEBUG
  380.     qprintf(patbuf);
  381. #endif
  382.  
  383.     if ((err = glob1(patbuf, pglob, no_match)) != 0)
  384.     return (err);
  385.  
  386.     /*
  387.      * If there was no match we are going to append the pattern 
  388.      * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
  389.      * and the pattern did not contain any magic characters
  390.      * GLOB_NOMAGIC is there just for compatibility with csh.
  391.      */
  392.     if (pglob->gl_pathc == oldpathc && 
  393.     ((flags & GLOB_NOCHECK) || 
  394.      ((flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR)))) {
  395.     if (!(flags & GLOB_QUOTE)) {
  396.         Char *dp = compilebuf;
  397.         const unsigned char *sp = compilepat;
  398.  
  399.         while ((*dp++ = *sp++) != '\0')
  400.         continue;
  401.     }
  402.     else {
  403.         /*
  404.          * copy pattern, interpreting quotes; this is slightly different
  405.          * than the interpretation of quotes above -- which should prevail?
  406.          */
  407.         while (*compilepat != EOS) {
  408.         if (*compilepat == QUOTE) {
  409.             if (*++compilepat == EOS)
  410.             --compilepat;
  411.         }
  412.         *compilebuf++ = (unsigned char) *compilepat++;
  413.         }
  414.         *compilebuf = EOS;
  415.     }
  416.     return (globextend(patbuf, pglob));
  417.     }
  418.     else if (!(flags & GLOB_NOSORT))
  419.     qsort((char *) (pglob->gl_pathv + pglob->gl_offs + oldpathc),
  420.           pglob->gl_pathc - oldpathc, sizeof(char *),
  421.           (int (*) __P((const void *, const void *))) compare);
  422.     return (0);
  423. }
  424.  
  425. static int
  426. glob1(pattern, pglob, no_match)
  427.     Char *pattern;
  428.     glob_t *pglob;
  429.     int     no_match;
  430. {
  431.     Char pathbuf[MAXPATHLEN + 1];
  432.  
  433.     /*
  434.      * a null pathname is invalid -- POSIX 1003.1 sect. 2.4.
  435.      */
  436.     if (*pattern == EOS)
  437.     return (0);
  438.     return (glob2(pathbuf, pathbuf, pattern, pglob, no_match));
  439. }
  440.  
  441. /*
  442.  * functions glob2 and glob3 are mutually recursive; there is one level
  443.  * of recursion for each segment in the pattern that contains one or
  444.  * more meta characters.
  445.  */
  446. static int
  447. glob2(pathbuf, pathend, pattern, pglob, no_match)
  448.     Char *pathbuf, *pathend, *pattern;
  449.     glob_t *pglob;
  450.     int     no_match;
  451. {
  452.     struct stat sbuf;
  453.     int anymeta;
  454.     Char *p, *q;
  455.  
  456.     /*
  457.      * loop over pattern segments until end of pattern or until segment with
  458.      * meta character found.
  459.      */
  460.     anymeta = 0;
  461.     for (;;) {
  462.     if (*pattern == EOS) {    /* end of pattern? */
  463.         *pathend = EOS;
  464.         if (Lstat(pathbuf, &sbuf))
  465.         return (0);
  466.  
  467.         if (((pglob->gl_flags & GLOB_MARK) &&
  468.          pathend[-1] != SEP) &&
  469.         (S_ISDIR(sbuf.st_mode)
  470. #ifdef S_IFLNK
  471.          || (S_ISLNK(sbuf.st_mode) &&
  472.              (Stat(pathbuf, &sbuf) == 0) &&
  473.              S_ISDIR(sbuf.st_mode))
  474. #endif
  475.          )) {
  476.         *pathend++ = SEP;
  477.         *pathend = EOS;
  478.         }
  479.         ++pglob->gl_matchc;
  480.         return (globextend(pathbuf, pglob));
  481.     }
  482.  
  483.     /* find end of next segment, copy tentatively to pathend */
  484.     q = pathend;
  485.     p = pattern;
  486.     while (*p != EOS && *p != SEP) {
  487.         if (ismeta(*p))
  488.         anymeta = 1;
  489.         *q++ = *p++;
  490.     }
  491.  
  492.     if (!anymeta) {        /* no expansion, do next segment */
  493.         pathend = q;
  494.         pattern = p;
  495.         while (*pattern == SEP)
  496.         *pathend++ = *pattern++;
  497.     }
  498.     else            /* need expansion, recurse */
  499.         return (glob3(pathbuf, pathend, pattern, p, pglob, no_match));
  500.     }
  501.     /* NOTREACHED */
  502. }
  503.  
  504.  
  505. static int
  506. glob3(pathbuf, pathend, pattern, restpattern, pglob, no_match)
  507.     Char *pathbuf, *pathend, *pattern, *restpattern;
  508.     glob_t *pglob;
  509.     int     no_match;
  510. {
  511.     extern int errno;
  512.     DIR    *dirp;
  513.     struct dirent *dp;
  514.     int     err;
  515.     Char m_not = (pglob->gl_flags & GLOB_ALTNOT) ? M_ALTNOT : M_NOT;
  516.  
  517.     *pathend = EOS;
  518.     errno = 0;
  519.  
  520.     if (!(dirp = Opendir(pathbuf)))
  521.     /* todo: don't call for ENOENT or ENOTDIR? */
  522.     if ((pglob->gl_errfunc && (*pglob->gl_errfunc) (pathbuf, errno)) ||
  523.         (pglob->gl_flags & GLOB_ERR))
  524.         return (GLOB_ABEND);
  525.     else
  526.         return (0);
  527.  
  528.     err = 0;
  529.  
  530.     /* search directory for matching names */
  531.     while ((dp = readdir(dirp)) != NULL) {
  532.     register unsigned char *sc;
  533.     register Char *dc;
  534.  
  535.     /* initial DOT must be matched literally */
  536.     if (dp->d_name[0] == DOT && *pattern != DOT)
  537.         continue;
  538.     for (sc = (unsigned char *) dp->d_name, dc = pathend; 
  539.          (*dc++ = *sc++) != '\0';)
  540.         continue;
  541.     if (match(pathend, pattern, restpattern, (int) m_not) == no_match) {
  542.         *pathend = EOS;
  543.         continue;
  544.     }
  545.     err = glob2(pathbuf, --dc, restpattern, pglob, no_match);
  546.     if (err)
  547.         break;
  548.     }
  549.     /* todo: check error from readdir? */
  550.     (void) closedir(dirp);
  551.     return (err);
  552. }
  553.  
  554.  
  555. /*
  556.  * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
  557.  * add the new item, and update gl_pathc.
  558.  *
  559.  * This assumes the BSD realloc, which only copies the block when its size
  560.  * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
  561.  * behavior.
  562.  *
  563.  * Return 0 if new item added, error code if memory couldn't be allocated.
  564.  *
  565.  * Invariant of the glob_t structure:
  566.  *    Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
  567.  *     gl_pathv points to (gl_offs + gl_pathc + 1) items.
  568.  */
  569. static int
  570. globextend(path, pglob)
  571.     Char *path;
  572.     glob_t *pglob;
  573. {
  574.     register char **pathv;
  575.     register int i;
  576.     unsigned int newsize;
  577.     char   *copy;
  578.     Char *p;
  579.  
  580.     newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
  581.     pathv = (char **) (pglob->gl_pathv ?
  582.                xrealloc((ptr_t) pglob->gl_pathv, (size_t) newsize) :
  583.                xmalloc((size_t) newsize));
  584.     if (pathv == NULL)
  585.     return (GLOB_NOSPACE);
  586.  
  587.     if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
  588.     /* first time around -- clear initial gl_offs items */
  589.     pathv += pglob->gl_offs;
  590.     for (i = pglob->gl_offs; --i >= 0;)
  591.         *--pathv = NULL;
  592.     }
  593.     pglob->gl_pathv = pathv;
  594.  
  595.     for (p = path; *p++;)
  596.     continue;
  597.     if ((copy = (char *) xmalloc((size_t) (p - path))) != NULL) {
  598.     register char *dc = copy;
  599.     register Char *sc = path;
  600.  
  601.     while ((*dc++ = *sc++) != '\0')
  602.         continue;
  603.     pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
  604.     }
  605.     pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
  606.     return ((copy == NULL) ? GLOB_NOSPACE : 0);
  607. }
  608.  
  609.  
  610. /*
  611.  * pattern matching function for filenames.  Each occurrence of the *
  612.  * pattern causes a recursion level.
  613.  */
  614. static  int
  615. match(name, pat, patend, m_not)
  616.     register Char *name, *pat, *patend;
  617.     int m_not;
  618. {
  619.     int ok, negate_range;
  620.     Char c, k;
  621.  
  622.     while (pat < patend) {
  623.     c = *pat++;
  624.     switch (c & M_MASK) {
  625.     case M_ALL:
  626.         if (pat == patend)
  627.         return (1);
  628.         do 
  629.         if (match(name, pat, patend, m_not))
  630.             return (1);
  631.         while (*name++ != EOS);
  632.         return (0);
  633.     case M_ONE:
  634.         if (*name++ == EOS)
  635.         return (0);
  636.         break;
  637.     case M_SET:
  638.         ok = 0;
  639.         if ((k = *name++) == EOS)
  640.         return (0);
  641.         if ((negate_range = ((*pat & M_MASK) == m_not)) != 0)
  642.         ++pat;
  643.         while (((c = *pat++) & M_MASK) != M_END) {
  644.         if ((*pat & M_MASK) == M_RNG) {
  645.             if (c <= k && k <= pat[1])
  646.             ok = 1;
  647.             pat += 2;
  648.         }
  649.         else if (c == k)
  650.             ok = 1;
  651.         }
  652.         if (ok == negate_range)
  653.         return (0);
  654.         break;
  655.     default:
  656.         k = *name++;
  657.         if (samecase(k) != samecase(c))
  658.         return (0);
  659.         break;
  660.     }
  661.     }
  662.     return (*name == EOS);
  663. }
  664.  
  665. /* free allocated data belonging to a glob_t structure */
  666. void
  667. globfree(pglob)
  668.     glob_t *pglob;
  669. {
  670.     register int i;
  671.     register char **pp;
  672.  
  673.     if (pglob->gl_pathv != NULL) {
  674.     pp = pglob->gl_pathv + pglob->gl_offs;
  675.     for (i = pglob->gl_pathc; i--; ++pp)
  676.         if (*pp)
  677.         xfree((ptr_t) *pp), *pp = NULL;
  678.     xfree((ptr_t) pglob->gl_pathv), pglob->gl_pathv = NULL;
  679.     }
  680. }
  681.